package com.apps.java.javanote02;

import java.io.*;

public class _23IO流_对象序列化流 {
    /**
     * 对象序列化流
     *
     * 	 一、概述：就是将对象保存到磁盘中，或者在网络中传输对象
     * 		这种机制就是使用一个字节序列表示一个对象，该字节序列包含：对象的类型、对象的数据和对象中存储的属性等信息
     * 		字节序列写到文件之后，相当于文件中持久保存了一个对象的信息；反之该字节序列还可以从文件中读取回来，重构对象，对它进行反序列化
     *
     * 	 二、要实现序列化和反序列化就要使用对象序列化流和对象反序列化流：
     * 		1.对象序列化流ObjectOutputStream
     * 			（1）概述：将java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取（重构）对象。
     * 					可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流，则可以在另一个主机上或另一个进程中重构对象。
     * 			（2）构造方法：
     * 					ObjectOutputStream(OutputStream out)：创建一个写入指定的OutputStream的ObjectOutputStream
     * 			（3）序列化对象的方法：
     * 					void writeObject(Object obj)：将指定的对象写入ObjectOutputStream
     * 		2.对象反序列化流
     * 			ObjectInputStream
     *
     *		3.注意事项：
     *			（1）一个对象要想被序列化，该对象所属的类必须实现Serializable接口。
     *			（2）NotSerializableException异常:抛出一个实例需要一个Serializable接口。序列化运行时或实例的类可能会抛出此异常。
     * 			（3）序列化接口没有方法或字段，仅用于标识可串行化的语义。
     *
     * 		4.对象反序列化流ObjectInputStream
     * 			（1）ObjectInputStream反序列化前先使用ObjectOuputStream编写的原始数据和对象
     * 			（2）构造方法：
     * 					ObjectInputStream(InputStream in)：创建从指定的InputStream读取的ObjectInputStream
     * 			（3）反序列化的方法：
     * 					Object readObject()：从ObjectStream读取一个对象
     *
     * 	三、对象序列化流的三个问题
     * 		1.用对象序列化流序列化了一个对象后，假如我们修改了对象所属的文件，读取数据会不会出现问题呢？
     * 			 报错：java.io.InvalidClassException: 	//当序列化运行时检测到类中的一下问题之一时抛出
     * 												//（1）类的串行版本与从流中读取的类描述符的类型不一致
     * 												//（2）该类包含未知的数据类型
     * 												//（3）该类没有可访问的无参数构造函数
     * 				com.apps.java.javanote02.Student; local class incompatible:
     * 				stream classdesc serialVersionUID = 1480515485187337050,//序列化运行时与每个可序列化的类关联一个版本号。
     * 																		//在反序列化过程中使用，以验证序列化对象的发送者和接收者是否加载了与学历恶化兼容的对象的类。
     * 				local class serialVersionUID = -2892723383256448850
     *
     * 		2.出现问题如何解决？
     * 			给对象所属的类加一个值：private static final long serialVersionUID = 421;
     *
     * 			一个可序列化的类可以通过声明一个名为“serialVersionUID”的字段来显式地声明它自己的serialVersionUID，该字段必须是static，final和long类型;
     * 			ANY-ACCESS-MODIFIER static final long serialVersionUID = 421;
     * 			如果可序列化类没有显式声明，则序列化运行时将根据java（TM）对象序列化规范中所述的类的各个方面计算该类的默认值。
     * 			强烈建议所有可序列化的类显式声明serialVersionUID值，因为默认的serialVersionUID计算对类的细节非常敏感，这些细节可能因编译器实现而异，因此会在反序列化时出现意外的异常。
     *
     * 		3.如果一个对象中的某个成员变量的值不想被序列化，又如何实现？
     * 			将类中成员变量用transient关键字修饰：private transient String address;
     *
     *
     *
     *
     *
     *
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException{

        //序列化对象
        //ObjectOutputStream(OutputStream out)：创建一个写入指定的OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));

        //创建学生对象
        Student stu = new Student("何锟",18,"大云汉it教育1007");

        //void writeObject(Object obj)：将指定的对象写入ObjectOutputStream
        oos.writeObject(stu);//NotSerializableException:抛出一个实例需要一个Serializable接口。序列化运行时或实例的类可能会抛出此异常。
        //类的序列化由实现java.io.Serializable接口的类启用。不识闲此接口的类将不会使任何状态序列化或反序列化

        //释放资源
        oos.close();

        //反序列化
        //ObjectInputStream(InputStream in)：创建从指定的InputStream读取的ObjectInputStream
        ObjectInputStream oin = new ObjectInputStream(new FileInputStream("oos.txt"));

        //Object readObject()：从ObjectStream读取一个对象
        Object obj = oin.readObject();

        //向上转型
        Student s = (Student)obj;

        System.out.println(s.getName() + "," + s.getAge() + "," + s.getAddress());

        //释放资源
        oin.close();


        //对象序列化流的三个问题
        write();
        read();

    }

    //反序列化
    private static void read() throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ois.txt"));
        Object obj = ois.readObject();
        Student s = (Student)obj;
        System.out.println(s.getName() + "," + s.getAge() + "," + s.getAddress());
        ois.close();
    }

    //序列化
    private static void write() throws IOException, IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ois.txt"));
        Student s = new Student("吴世勋",28,"首尔");
        oos.writeObject(s);
        oos.close();
    }
}
